import os
import shutil

from utils.utils import Utils
from utils.executor import Executor
from common.benchmark_var import GlobalEnv, ConfigSections, StatusCode
from common.logger import log
from framework.base_workload import BaseWorkload


class NativeWorkload(BaseWorkload):
    def __init__(self, name, options, baseline):
        super().__init__(name, options, baseline)
        self.use_makefile = False
        self.no_build = False

    def build(self):
        if self.no_build:
            return

        log.info("build workload : {}...".format(self.name))
        if self.use_makefile:
            self.gen_makefile_config(self.options.get(ConfigSections.COMPILER))
            make_res = self.makefile_build()
            if not make_res:
                Utils.print_err_code(StatusCode.BUILD_FAIL,
                                     "check {} log in {}".format(self.name, self.build_dir))
        else:
            self.gen_cmake_config(self.options.get(ConfigSections.COMPILER))
            configure_res = self.cmake_configure()
            build_res = self.cmake_build()
            if not configure_res or not build_res:
                Utils.print_err_code(StatusCode.BUILD_FAIL,
                                     "check {} log in {}".format(self.name, self.build_dir))
        if not self.build_extend_tool():
            Utils.print_err_code(StatusCode.BUILD_EXTEND_TOOL_FAIL,
                                 "check {} log in {}".format(self.name, self.build_dir))

        self.copy_exe2bin()

    def makefile_build(self):
        return True

    def check_program(self):
        bin_dir_files = os.listdir(self.bin_dir)
        for program in self.program:
            if program not in bin_dir_files:
                exit('program: {} not found'.format(program))

    def cmake_configure(self):
        cmake_h = self.src_dir
        cmake_b = self.build_dir
        executor = Executor(desc='configure',
                            command='cmake -H{} -B{}'.format(cmake_h, cmake_b),
                            exec_dir=self.build_dir,
                            debug=self.debug)
        res = executor.exec()
        if res != 0:
            return False
        else:
            return True

    def cmake_build(self):
        executor = Executor(desc='make',
                            command='make -j install',
                            exec_dir=self.build_dir,
                            debug=self.debug)

        res = executor.exec()
        if res != 0:
            return False
        else:
            return True

    def gen_cmake_config(self, build_info):
        """
        generate build_config.cmake to control building
        :param build_info: build config
        :return:
        """
        build_config = os.path.join(self.build_dir, 'build_config.cmake')
        if not os.path.exists(build_config):
            cmake_template = os.path.join(GlobalEnv.GCBS_UTILS_DIR, "cmake_settings.cmake")
            with open(cmake_template, 'r') as template:
                cmake_template_content = template.read()

            with open(build_config, 'w+') as config:
                config.write("message(STATUS build config)\n")
                for setting in build_info:
                    config.write("SET({} {})\n".format(setting, build_info.get(setting)))

                config.write(cmake_template_content)

    def gen_makefile_config(self, build_info):
        """
        generate build_config.mk to control building
        :param build_info: build config
        :return:
        """
        build_config = os.path.join(self.build_dir, 'build_config.mk')
        if not os.path.exists(build_config):
            with open(build_config, 'w+') as config:
                for setting in build_info:
                    config.write("{}={}\n".format(setting, build_info.get(setting)))

    def copy_src2build(self, files=None):
        if not files:
            files = os.listdir(self.src_dir)
        for file in files:
            src_file = os.path.join(self.src_dir, file)
            dst_file = os.path.join(self.build_dir, file)
            if os.path.exists(dst_file):
                shutil.rmtree(dst_file) if os.path.isdir(dst_file) else os.remove(dst_file)
            if os.path.isdir(src_file):
                shutil.copytree(src_file, dst_file)
            else:
                shutil.copy(src_file, self.build_dir)

    def copy_exe2bin(self):
        return
